<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div id="app" style="color: red; font-size: 12px">
      hello: {{name}} hello: {{c.c.name}}
      <h1>我是子h1标签</h1>
      <h3>{{listObj}}</h3>

      <h1>下面用到了diff算法: 开始内部自己实现diff算法的逻辑</h1>
      <i>1.vue中操作 vnode {tag: 'div',data: children}</i>
      <br />
      <i>2. 真正DOM 特别多 会消耗性能</i>
      <br />
      <i>3. 更新数据 vue diff算法 最小量更新（比对）vnode(old,new)</i>
      <br />
      <i
        >4.案例：小试牛刀==> 创建两个vnode,比对 当数据更新的时候拿到老的节点
        和新的节点 做对比，将不同的地方进行dom的更新
      </i>
      <hr />
    </div>
    <script src="dist/vue.js"></script>
    <script>
      //umd Vue
      // //console.log(Vue,"Vue") 调用Vue.mixin()
      Vue.Mixin({
        // vue全局混入方法 每个vue实例 都能访问到
        created: function a() {
          //订阅
          console.log("我是全局的生命周期我比组件内的生命周期先执行a");
        },
      });
      Vue.Mixin({
        // vue全局混入方法 每个vue实例 都能访问到
        created: function b() {
          //订阅
          console.log("我是全局的生命周期我比组件内的生命周期先执行b");
        },
      });
      //响应式 vue2 mvvm
      let vm = new Vue({
        el: "#app",
        data() {
          //console.log(this,"要保证this是当前vue实列对象")
          return {
            name: "张思佳阿菊",
            obj: {
              name: "zxy测试002",
            },
            list: [
              {
                sex: "男",
              },
            ],
            listObj: [
              {
                a: 1,
              },
            ],
            c: {
              c: {
                name: "ccc踩踩菜",
              },
            },
          };
        },
        created() {
          //发布created方法
          console.log(555, this, "定义的方法组件内的created钩子函数");
          // return console.log('阻止created继续往下走代码逻辑')
          // 0.接着实现 根据观察者模式 进行依赖收集-数据更新-自动更新视图
          setTimeout(() => {
            // 1. 模拟 数据更新 视图更新的方法
            this.name = "张永全张沐阳冯海霞张旭阳";
            this.c.c.name = "大的cc";
            // this._update(this._render()); //自动更新视图 其实是手动调用这两个方法 _render将render函数转成vNode虚拟dom,_update将vNode虚拟dom转成真实dom

            // 2. 数组更新，观察者模式，收集依赖
            this.listObj.push({
              b: 555,
            });
            this.listObj.push({
              newAge: 14,
            });

            //3. 连续两次push 会连续两次进行 render函数==》vnode虚拟dom==>转真实dom 调用多次this._update(this._render())
            // 3.2 所以使用队列处理 也就是this.$nextTick(() => {})的实现原理
            // 3.3 目的实现 多次调用的方法 只调用一次
            // 3.4 批量处理 ==》 vue异步  数据更新后 不会马上执行
            //用户用法：需要在Vue原型上定义该方法
            this.$nextTick(() => {
              //可以获取当前实例对象上所有的属性或者方法
              console.log(
                "[用户调用$nextTick 可以在回调函数内获取最新的dom]",
                this,
              );
            });
          }, 2000);
          // 1. 问题 如何自动更新 不用手动调用 vm._update(vm._render())这两个方法
          // 1.1 数据变化  自动更新视图  其实是在合适位置调用这两个方法  vm._update(vm._render()) )_render把render函数转vnode  _update把vNode转真实dom
          //1.2 vue中更新组件策略是：：以组件为单位，给每一个组件（会转成render函数）添加一个watcher,也就是render函数为单位，属性变化后，调用找个watcher

          //2.  实现对象的收集依赖 （通过观察者模式）

          //2.1 dep和 watcher关系  多对多 是为了计算属性

          //3. 数组收集依赖
          //3.1 我们要给所有对象类型的增加一个dep  []
          //3.2 获取数组的值，会调用get方法，希望让当前的数组记住个渲染的watcher
          //3.2.1 获取当前dep
          //3.2.2 当前面对数组取值的时候，我们就让数组的dep记住这个watcher
          //3.2.3 我们更新数组的时候 调用push,等等方法 找到我们这个watcher进行更新
        },
        updated() {
          console.log("updated");
        },
        // 实现watch功能
        // watch调用的三种方法
        //1. 属性: function(newVal,oldVal) 方法
        //2. 属性: [() => {},() => {}] 数组
        //3. 属性: {handler(newVal,oldVal) {},immediate: true,deep: true } 对象的形式
        watch: {
          name: function (newVal, oldVal) {
            //默认是一个函数
            //
            console.log(
              newVal,
              "newVal",
              oldVal,
              "oldVal<br/>",
              this,
              "this<br/>",
              this.name,
              "this.name<br/>",
              "watch---并且通过call来改变this指向监听的原理监听",
            );
            this.name = "我叫" + this.name;
          },
          "c.c.name"(newVal, oldVal) {
            console.log(newVal, oldVal, "watch--ccc");
          },
          obj: {
            handler(newVal, oldVal) {},
            immediate: true,
            deep: true,
          },
        },
      });
      //console.log(vm,"vm--每一个组件对象")

      //1.0   vm.msg = vm._data.msg 代理 可以直接通过vm实列也就是this访问msg
      //1.1    vue初次渲染===> 先初始化数据===> 将模板进行编译===> 编译成render函数 render() => 生成虚拟节点 ==> 变成真实的DOM ==> 放到页面上
      // vue模板编译  template render el  注意: el（必须挂载到指定容器上，应用才会生效呀）

      //2.  vue的生命周期 实现的原理 源码实现
      // 2.1核心点使用全局混入 Vue.mixin({})
      // 2.2 是用设计模型 订阅发布 vue options:{data: [],watch: []}
    </script>
  </body>
</html>
